09. Interact with a Single Element

Interact with a Single Element

Question:

Start Quiz:

<!DOCTYPE html>

<!--
Unfortunately, this quiz will not be graded. If you do it correctly, the slider should respond to
touch and mouse events smoothly.
-->

<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>Quiz - Touch Slider</title>
	<link rel="stylesheet" href="css/styles.css">
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
</head>
<body>
	<div class="main">
		<h3>Slide me</h3>
		<div class="slider-main">
			<svg id="line" height="48" width="300">
				<line x1="0" y1="24" x2="300" y2="24" style="stroke:rgb(0,0,0);stroke-width:2" />
			</svg>
			<div id="toggle"><div class="markings">|||</div></div>
		</div>
	</div>
	<script src="js/app.js"></script>
	<script>
		/*
		No need to touch! Just blocks accidental scrolling
		 */

		// http://stackoverflow.com/questions/16348031/disable-scrolling-when-touch-moving-certain-element
		window.blockMenuHeaderScroll = false;
		$(window).on('touchstart', function(e) {
			if ($(e.target).closest('.main').length == 1) {
				blockMenuHeaderScroll = true;
			}
		});
		$(window).on('touchend', function() {
			blockMenuHeaderScroll = false;
		});
		$(window).on('touchmove', function(e) {
			if (blockMenuHeaderScroll) {
				e.preventDefault();
			}
		});
	</script>
</body>
</html>
(function() {
/*
Write your code in the attachEventListeners() function defintion, which starts on line 88.
*/

/*
The actual grey box your finger touches.
 */
var toggle = document.querySelector('#toggle');
/*
The line that the toggle slides over.
 */
var line = document.querySelector('#line');

/**
 * Keeps track of touches and determines where the toggle should be on the slider.
 * @param {DOM node} toggle - The actual toggle that will be moving.
 * @param {DOM node} line - The actual line that the toggle slides over.
 */
function ToggleTracker (toggle, line) {
	var toggleRect = toggle.getBoundingClientRect();
	var lineRect = line.getBoundingClientRect();
	
	this._max = lineRect.width - toggleRect.width;
	this._half = this._max / 2;
	
	this._touchOffset = 0;
}

ToggleTracker.prototype = {
	_touches: [],
	/**
	 * Call this to register a movement.
	 * @param {Number} posX - The current x-position of the finger/mouse.
	 */
	addMovement: function (posX) {
		this._touches[0] = this._touches[1] || posX;
		this._touches[1] = posX;
	},
	/*
	Call this to get the toggle's distance from the origin for
	the CSS property: transform: translateX()
	 */
	getTranslateX: function () {		
		/*
		How far the finger actually moved
		 */
		var dx = this._touches[1] - this._touches[0];
		
		/*
		transform: translateX() works by translating from a starting point. The idea is to
		sum every dx to find the current distance from the origin.
		 */
		this._touchOffset = this._touchOffset + dx;

		/*
		I don't want to overwrite _touchOffset as it needs to stay constant between touches.
		 */
		var reportedValue = this._touchOffset;

		/*
		Make sure the toggle doesn't slide off the slider!
		 */
		if (reportedValue < 0) {
			reportedValue = 0;
		} else if (reportedValue > this._max) {
			reportedValue = this._max;
		}

		return reportedValue;
	}
};

/*
You could create multiple ToggleTrackers for multiple toggles.
 */
var toggleTracker = new ToggleTracker(toggle, line);

/*
Meant to be called by requestAnimationFrame for silky smooth 60fps performance.
#perfmatters - https://www.udacity.com/course/browser-rendering-optimization--ud860
 */
function slide() {
	var translateX = toggleTracker.getTranslateX();
	toggle.style.webkitTransform = "translateX(" + translateX + "px)";
	toggle.style.transform = "translateX(" + translateX + "px)";
}

function attachEventListeners() {
	/*
	The idea is:
		1) On start, set flag that toggle has started sliding (sliding = true). Attach the event to the toggle itself and add the first movement.
		2) On move, if sliding has been activated, then register a new movement and animate the move.
		Movement doesn't need to be limited to the toggle as it's easy for a finger/mouse to slip off.
		3) On end, set flag that the toggle has stopped sliding. Once again, it doesn't need to be limited to the toggle as the finger/mouse can come up anywhere in the window.
	 */

	/*
	Your code goes here!
	 */
}

var sliding = false;
attachEventListeners();
})();
Solution:

INSTRUCTOR NOTE:

Event Listeners on MDN

Touch Events on MDN

Follow us online!

@cwpittman

@greenido

+greenido

Unfortunately, this quiz is not graded because it's tricky to reliably simulate touch and mouse events. You'll know you've completed this quiz when the toggle sticks to your finger/mouse and slides nicely.
You can either work in the classroom here or you can find a copy of the code to download and run in the Downloadables section.